package top.kaoshanji.p2chapters.mapper;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Test;
import top.kaoshanji.p2chapters.model.SysPrivilege;
import top.kaoshanji.p2chapters.model.SysRole;
import top.kaoshanji.p2chapters.model.SysUser;

import java.util.*;

/**
 * @author kaoshanji
 * ^_^
 * create time 2025/4/13 9:38
 */
public class UserMapperTest extends BaseMapperTest {

    private static final Logger logger = LogManager.getLogger(UserMapperTest.class);

    /**
     * 代码清单test-p2chapters-30页a：测试通过id查询用户
     */
    @Test
    public void testSelectById() {
        // 获取 sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            // 获取 UserMapper 接口
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 调用 selectById 方法，查询 id = 1 的用户
            SysUser user = userMapper.selectById(1L);
            // user 不为空
            Assert.assertNotNull(user);
            // userName = admin
            Assert.assertEquals("admin", user.getUserName());
        } finally {
            // 不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-30页b：测试查询全部用户
     */
    @Test
    public void testSelectAll() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 调用 selectAll 方法查询所有用户
            List<SysUser> userList = userMapper.selectAll();
            // 结果不为空
            Assert.assertNotNull(userList);
            // 用户数量大于0个
            Assert.assertTrue(userList.size() > 0);
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-32页a：测试根据用户id获取角色信息
     */
    @Test
    public void testSelectRolesByUserId() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<SysRole> roleList = userMapper.selectRolesByUserId(1L);
            Assert.assertNotNull(roleList);
            Assert.assertTrue(roleList.size() > 0);
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-33页a：测试根据用户id获取角色信息V1版
     */
    @Test
    public void testSelectRolesByUserIdV1() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<SysRole> roleList = userMapper.selectRolesByUserIdV1(1L);
            Assert.assertNotNull(roleList);
            Assert.assertTrue(roleList.size() > 0);
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-37页a：测试新增用户
     */
    @Test
    public void testInsert() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser user = new SysUser();
            user.setUserName("test1");
            user.setUserPassword("123456");
            user.setUserEmail("test@mybatis.tk");
            user.setUserInfo("test info");
            user.setHeadImg(new byte[]{1,2,3});
            user.setCreateTime(new Date());

            // 将新建的对象插入数据库中，特别注意这里的返回值 result 是执行的 SQL 影响的行数
            int result = userMapper.insert(user);

            // 只插入 1 条数据
            Assert.assertEquals(1, result);

            // id 为 null，没有给 id 赋值，并且没有配置回写 id 的值
            Assert.assertNull(user.getId());
        } finally {
            // 为了不影响其他测试，这里选择回滚
            // 由于默认的 sqlSessionFactory.openSession() 是不自动提交的
            // 因此不手动执行 commit 也不会提交到数据库
            sqlSession.rollback();
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-39页a：测试新增用户，返回自增主键
     */
    @Test
    public void testInsert2() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser user = new SysUser();
            user.setUserName("test1");
            user.setUserPassword("123456");
            user.setUserEmail("test@mybatis.tk");
            user.setUserInfo("test info");
            user.setHeadImg(new byte[]{1,2,3});
            user.setCreateTime(new Date());

            int result = userMapper.insert2(user);

            // 只插入 1 条数据
            Assert.assertEquals(1, result);

            // 因为 id 回写，所以 id 不为 null
            Assert.assertNotNull(user.getId());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }

    }

    /**
     * 代码清单test-p2chapters-43页a：测试根据主键更新
     */
    @Test
    public void testUpdateById() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 从数据库查询1个 user 对象
            SysUser user = userMapper.selectById(1L);
            // 当前 userName 为 admin
            Assert.assertEquals("admin", user.getUserName());
            // 修改用户名
            user.setUserName("admin_test");
            // 修改邮箱
            user.setUserEmail("test@mybatis.tk");

            // 更新数据，特别注意，这里的返回值 result 是执行的 SQL 影响的行数
            int result = userMapper.updateById(user);

            // 只更新 1 条数据
            Assert.assertEquals(1, result);
            // 根据当前 id 查询修改后的数据
            user = userMapper.selectById(1L);
            // 修改后的名字是 admin_test
            Assert.assertEquals("admin_test", user.getUserName());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-45页a：测试通过主键删除
     */
    @Test
    public void testDeleteById() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 从数据库查询 1 个 user 对象，根据 id = 1 查询
            SysUser user1 = userMapper.selectById(1L);
            // 现在还能查询出 user 对象
            Assert.assertNotNull(user1);

            // 调用方法删除
            Assert.assertEquals(1, userMapper.deleteById(1L));
            // 再次查询，这时应该没有值，为null
            Assert.assertNull(userMapper.selectById(1L));

            // 使用 SysUser 参数再进行一次测试，根据 id = 1001 查询
            SysUser user2 = userMapper.selectById(1001L);
            // 现在还能查询出 user 对象
            Assert.assertNotNull(user2);
            // 调用方法删除，注意这里使用参数为 user2
            Assert.assertEquals(1, userMapper.deleteById(user2));
            // 再次查询，这时应该没有值，为 null
            Assert.assertNull(userMapper.selectById(1001L));
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-66页a：测试根据动态条件查询用户信息
     */
    @Test
    public void testSelectByUser() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            logger.info("...只查询用户名时...");
            SysUser query = new SysUser();
            query.setUserName("ad");
            List<SysUser> userList = userMapper.selectByUser(query);
            Assert.assertTrue(userList.size() > 0);

            logger.info("...只查询用户邮箱时...");
            query = new SysUser();
            query.setUserEmail("test@mybatis.tk");
            userList = userMapper.selectByUser(query);
            Assert.assertTrue(userList.size() > 0);

            logger.info("...当同时查询用户名和邮箱时...");
            query = new SysUser();
            query.setUserName("ad");
            query.setUserEmail("test@mybatis.tk");
            userList = userMapper.selectByUser(query);
            // 由于没有同时符合这两个条件的用户，因此查询结果数为 0
            Assert.assertTrue(userList.size() == 0);

        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-69页a：测试根据主键更新
     */
    @Test
    public void testUpdateByIdSelective() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 创建一个新的 user 对象
            SysUser user = new SysUser();
            // 更新 id = 1 的用户
            user.setId(1L);
            // 修改邮箱
            user.setUserEmail("test@mybatis.tk");
            // 更新邮箱，特别注意，这里的返回值 result 执行的是 SQL 影响的行数
            int result = userMapper.updateByIdSelective(user);
            // 只更新 1 条数据
            Assert.assertEquals(1, result);
            // 根据当前 id 查询修改后的数据
            user = userMapper.selectById(1L);
            // 修改后的名字保持不变，但是邮箱变成了新的
            Assert.assertEquals("admin", user.getUserName());
            Assert.assertEquals("test@mybatis.tk", user.getUserEmail());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-71页a：测试有id标签的插入数据
     */
    @Test
    public void testInsert3() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            // 创建一个 user 对象
            SysUser user = new SysUser();
            user.setUserName("test-selective");
            user.setUserPassword("123456");
            user.setUserInfo("test info");
            user.setCreateTime(new Date());

            // 插入数据库
            userMapper.insert3(user);
            // 获取插入的这条数据
            user = userMapper.selectById(user.getId());
            Assert.assertEquals("test@mybatis.tk", user.getUserEmail());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-73页a：测试根据用户id或用户名查询
     */
    @Test
    public void testSelectByIdOrUserName() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            logger.info("...只查询用户名时...");
            SysUser query = new SysUser();
            query.setId(1L);
            query.setUserName("admin");
            SysUser user = userMapper.selectByIdOrUserName(query);
            Assert.assertNotNull(user);

            logger.info("...当没有id时...");
            query.setId(null);
            user = userMapper.selectByIdOrUserName(query);
            Assert.assertNotNull(user);

            logger.info("...当id和name都为空时...");
            query.setUserName(null);
            user = userMapper.selectByIdOrUserName(query);
            Assert.assertNull(user);
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-75页a：测试根据动态条件查询用户信息（where标签版本）
     */
    @Test
    public void testSelectByUser1() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            logger.info("...只查询用户名时...");
            SysUser query = new SysUser();
            query.setUserName("ad");
            List<SysUser> userList = userMapper.selectByUser1(query);
            Assert.assertTrue(userList.size() > 0);

            logger.info("...只查询用户邮箱时...");
            query = new SysUser();
            query.setUserEmail("test@mybatis.tk");
            userList = userMapper.selectByUser1(query);
            Assert.assertTrue(userList.size() > 0);

            logger.info("...当同时查询用户名和邮箱时...");
            query = new SysUser();
            query.setUserName("ad");
            query.setUserEmail("test@mybatis.tk");
            userList = userMapper.selectByUser1(query);
            // 由于没有同时符合这两个条件的用户，因此查询结果数为 0
            // 数据好像被改过了..导致失败了...
            Assert.assertTrue(userList.size() == 0);

        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-76页a：测试根据主键更新（set标签版本）
     */
    @Test
    public void testUpdateByIdSelective1() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 创建一个新的 user 对象
            SysUser user = new SysUser();
            // 更新 id = 1 的用户
            user.setId(1L);
            // 修改邮箱
            user.setUserEmail("test@mybatis.tk");
            // 更新邮箱，特别注意，这里的返回值 result 执行的是 SQL 影响的行数
            int result = userMapper.updateByIdSelective1(user);
            // 只更新 1 条数据
            Assert.assertEquals(1, result);
            // 根据当前 id 查询修改后的数据
            user = userMapper.selectById(1L);
            // 修改后的名字保持不变，但是邮箱变成了新的
            Assert.assertEquals("admin", user.getUserName());
            Assert.assertEquals("test@mybatis.tk", user.getUserEmail());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-80页a：测试根据用户id集合查询
     */
    @Test
    public void testSelectByIdList() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            List<Long> idList = new ArrayList<>();
            idList.add(1L);
            idList.add(1001L);

            // 业务逻辑中必须校验 idList.size() > 0
            List<SysUser> userList = userMapper.selectByIdList(idList);
            Assert.assertEquals(2, userList.size());
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-82页a：测试批量插入用户信息
     */
    @Test
    public void testInsertList() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 创建一个 user 对象
            List<SysUser> userList = new ArrayList<>();
            for (int i = 0; i < 2; i++) {
                SysUser user = new SysUser();
                user.setUserName("test" + i);
                user.setUserPassword("1234456");
                user.setUserEmail("test@mybatis.tk");
                userList.add(user);
            }

            // 将新建的对象批量插入数据库中
            // 特别注意，这里的返回值 result 是执行 SQL 影响的行数
            int result = userMapper.insertList(userList);
            Assert.assertEquals(2, result);
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-84页a：测试通过 map 更新列
     */
    @Test
    public void testUpdateByMap() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            Map<String, Object> map = new HashMap<>();
            // 查询条件，同样也是更新字段，必须保持该值存在
            map.put("id", 1L);
            // 要更新的其他字段
            map.put("user_email", "test@mybatis.tk");
            map.put("user_password", "12345678");

            // 更新数据
            userMapper.updateByMap(map);

            // 根据当前 id 查询修改后的数据
            SysUser user = userMapper.selectById(1L);
            Assert.assertEquals("test@mybatis.tk", user.getUserEmail());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-128页a：测试根据用户 id 获取用户信息和用户的角色信息
     */
    @Test
    public void testSelectUserAndRoleById() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 特别注意，在测试户数中， id = 1L 的用户有两个角色，不适合这个例子
            // 这里使用只有一个角色的用户（ id = 1001L）
            SysUser user = userMapper.selectUserAndRoleById(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            Assert.assertNotNull(user.getRole());
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-131页a：测试根据用户 id 获取用户信息和用户的角色信息（resultMap配置版本）
     */
    @Test
    public void testSelectUserAndRoleById2() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 特别注意，在测试户数中， id = 1L 的用户有两个角色，不适合这个例子
            // 这里使用只有一个角色的用户（ id = 1001L）
            SysUser user = userMapper.selectUserAndRoleById2(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            Assert.assertNotNull(user.getRole());
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-133页a：测试根据用户 id 获取用户信息和用户的角色信息（association配置版本）
     */
    @Test
    public void testSelectUserAndRoleById3() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 特别注意，在测试户数中， id = 1L 的用户有两个角色，不适合这个例子
            // 这里使用只有一个角色的用户（ id = 1001L）
            SysUser user = userMapper.selectUserAndRoleById3(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            Assert.assertNotNull(user.getRole());
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-135页a：测试根据用户 id 获取用户信息和用户的角色信息（association标签的嵌套查询）
     */
    @Test
    public void testSelectUserAndRoleByIdSelect() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户（ id = 1001L ）
            SysUser user = userMapper.selectUserAndRoleByIdSelect(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            // user.role 也不为空
            Assert.assertNotNull(user.getRole());
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-137页a：测试根据用户 id 获取用户信息和用户的角色信息（延迟加载）
     */
    @Test
    public void testSelectUserAndRoleByIdSelect1() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户（ id = 1001L ）
            SysUser user = userMapper.selectUserAndRoleByIdSelect1(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            System.out.println("...调用user.getRole()..."); // 先输出
            Assert.assertNotNull(user.getRole()); // 再加载
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-139页a：测试根据用户 id 获取用户信息和用户的角色信息（延迟加载之加载全部数据版本）
     */
    @Test
    public void testSelectUserAndRoleByIdSelect2() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 这里使用只有一个角色的用户（ id = 1001L ）
            SysUser user = userMapper.selectUserAndRoleByIdSelect1(1001L);
            // user 不为空
            Assert.assertNotNull(user);
            System.out.println("调用user.equals(null)");
            // 在延迟加载的情况下，触发该方法将所有数据都加载出来
            user.equals(null); // 此时就把全部数据加载出来了
            System.out.println("...调用user.getRole()..."); // 后输出了
           // Assert.assertNotNull(user.getRole()); // 可以注释掉了
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-142页a：测试获取所有的用户以及对应的所有角色
     */
    @Test
    public void testSelectAllUserAndRoles() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<SysUser> userList = userMapper.selectAllUserAndRoles();
            System.out.println("用户数：" + userList.size());
            for (SysUser user: userList) {
                String userName = user.getUserName();
                System.out.println("用户名：" + userName);
                for (SysRole role: user.getRoleList()) {
                    System.out.println("角色名：" + userName + " - " + role.getRoleName());
                }
            }
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-148页a：测试用户有多个角色，每个角色有多个权限
     */
    @Test
    public void testSelectAllUserAndRoles1() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<SysUser> userList = userMapper.selectAllUserAndRoles1();
            System.out.println("用户数：" + userList.size());
            for (SysUser user: userList) {
                String userName = user.getUserName();
                System.out.println("用户名：" + userName);
                for (SysRole role: user.getRoleList()) {
                    String roleName = role.getRoleName();
                    System.out.println("角色名：" + userName + " - " + roleName);
                    for (SysPrivilege privilege: role.getPrivilegeList()) {
                        System.out.println("权限名：" + userName + "-" + roleName + "-" + privilege.getPrivilegeName());
                    }
                }
            }
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 代码清单test-p2chapters-154页a：测试嵌套查询指定用户的信息以及用户的角色和权限信息
     */
    @Test
    public void testSelectAllUserAndRolesSelect() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            SysUser user = userMapper.selectAllUserAndRolesSelect(1L);

            String userName = user.getUserName();
            System.out.println("用户名：" + userName);

            for (SysRole role: user.getRoleList()) {
                String roleName = role.getRoleName();
                System.out.println("角色名：" + userName + " - " + roleName);

                for (SysPrivilege privilege: role.getPrivilegeList()) {
                    System.out.println("权限名：" + userName + "-" + roleName + "-" + privilege.getPrivilegeName());
                }
            }
        } finally {
            sqlSession.close();
        }
    }



}
